use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
use serde::{Deserialize, Serialize};
use tracing::debug;
use crate::argument::Argument;
use crate::c::CONFIG_FILE_NAME;
use crate::util::Util;

#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
    port: u16,
    upstream: SocketAddr,
    unity: String,
}

impl Default for Config {
    fn default() -> Self {
        Self {
            port: 11851,
            upstream: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 11852)),
            unity: "unity".to_string(),
        }
    }
}

impl Config {
    pub fn default_port() -> u16 {
        11851
    }

    pub fn with_argument(argument: &Argument) -> Self {
        let p = argument
            .config_path()
            .clone()
            .unwrap_or_else(|| Util::app_dirs().config_dir().join(CONFIG_FILE_NAME));

        debug!("optional config source: {:?}", p);

        let mut c: Config = config::Config::builder()
            .add_source(config::File::with_name(p.to_str().unwrap()).required(false))
            .set_override_option("port", argument.port().clone()).unwrap()
            .build().unwrap()
            .try_deserialize().unwrap();

        if let Some(upstream) = argument.upstream() {
            c.upstream = upstream.clone();
        }

        c
    }

    pub fn port(&self) -> &u16 {
        &self.port
    }

    pub fn upstream(&self) -> &SocketAddr {
        &self.upstream
    }
}

#[cfg(test)]
mod tests {
    use crate::config::Config;

    #[test]
    fn gen_default_config() {
        let config = Config::default();

        let s = toml::to_string(&config).unwrap();
        println!("{}", s);
    }
}